package com.dh.shiro.config;

import java.util.LinkedHashMap;

import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.dh.shiro.realm.AuthRealm;
import com.dh.shiro.realm.CredentialsMatcher;

/**
 * @author 作者 dinghao
 * @version 创建时间：2018年11月26日 下午3:19:46
 * @Description 类说明 : shiro配置类
 */
@Configuration
public class ShiroConfig {

	/**
	 * 
	 * @Title: credentialsMatcher
	 * @author
	 * @Description: 密码校验规则
	 * @return
	 * @return CredentialsMatcher
	 */
	@Bean("credentialsMatcher")
	public CredentialsMatcher credentialsMatcher() {
		return new CredentialsMatcher();
	}

	@Bean("authRealm")
	public AuthRealm authRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
		AuthRealm authRealm = new AuthRealm();
		// 将认证缓存到cacheManager中
		authRealm.setCacheManager(new MemoryConstrainedCacheManager());
		// 密码匹配解析器(自定义密码校验规则)
		authRealm.setCredentialsMatcher(matcher);
		return authRealm;
	}

	@Bean("securityManager")
	public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
		DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
		manager.setRealm(authRealm);
		return manager;
	}

	@Bean("shiroFilter")
	public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {
		ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
		bean.setSecurityManager(manager);

		bean.setLoginUrl("/loginUser");
		bean.setSuccessUrl("/index");
		bean.setUnauthorizedUrl("/unauthorized");

		// 不同请求的拦截
		LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		/*
		 * DefaultFilter 
		 * anon:例子/admins/**=anon 没有参数，表示可以匿名使用。
		 * authc:例如/admins/user/**=authc表示需要认证(登录)才能使用，没有参数
		 * roles(角色)：例子/admins/user/**=roles[admin],参数可以写多个，多个时必须加上引号，并且参数之间用逗号分割，
		 * 当有多个参数时，例如admins/user/**=roles["admin,guest"],每个参数通过才算通过，相当于hasAllRoles()方法。
		 * perms（权限）：例子/admins/user/**=perms[user:add:*],参数可以写多个，多个时必须加上引号，并且参数之间用逗号分割，
		 * 例如/admins/user/**=perms["user:add:*,user:modify:*"]，当有多个参数时必须每个参数都通过才通过，
		 * 想当于isPermitedAll()方法。
		 * rest：例子/admins/user/**=rest[user],根据请求的方法，相当于/admins/user/**=perms[user:
		 * method] ,其中method为post，get，delete等。
		 * port：例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:
		 * 8081?queryString,其中schmal是协议http或https等，serverName是你访问的host,
		 * 8081是url配置里port的端口，queryString 是你访问的url里的？后面的参数。
		 * authcBasic：例如/admins/user/**=authcBasic没有参数表示httpBasic认证
		 * ssl:例子/admins/user/**=ssl没有参数，表示安全的url请求，协议为https
		 * user:例如/admins/user/**=user没有参数表示必须存在用户，当登入操作时不做检查
		 */
		filterChainDefinitionMap.put("/loginUser", "anon");
		filterChainDefinitionMap.put("/login", "anon");
		// 放行swagger
		filterChainDefinitionMap.put("/swagger-ui.html", "anon");
		filterChainDefinitionMap.put("/swagger-resources", "anon");
		filterChainDefinitionMap.put("/v2/api-docs", "anon");
		filterChainDefinitionMap.put("/webjars/springfox-swagger-ui/**", "anon");
		
		filterChainDefinitionMap.put("/index", "authc");
		// 必须放在"/**", "user"之前否则通过角色控制权限无效
		filterChainDefinitionMap.put("/admin", "roles[admin]");
		filterChainDefinitionMap.put("/edit", "perms[edit]");
		// 使用druid作为连接池
		filterChainDefinitionMap.put("/druid/**", "anon");
		filterChainDefinitionMap.put("/**", "user");
		
		

		bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return bean;
	}

	/*
	 * shiro与spring的关联
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
			@Qualifier("securityManager") SecurityManager manager) {
		AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
		advisor.setSecurityManager(manager);
		return advisor;
	}

	@Bean
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
		creator.setProxyTargetClass(true);
		return creator;
	}
}
